using System;
using System.Collections.Generic;

namespace DanielSig
{
	public static class XLinkedList
	{
		public static void AddSorted<T>(this LinkedList<T> list, T value, Func<T,float> test)
		{
			float testValue = test(value);
			LinkedListNode<T> larger = null;
			LinkedListNode<T> current = list.First;
			while(current != null)
			{
				if(test(current.Value) > testValue)
				{
					larger = current;
					break;
				}
				current = current.Next;
			}
			if(larger == null)
				list.AddLast(value);
			else
				list.AddBefore(larger, value);
		}
		public static LinkedListNode<T> NodeAt<T>(this LinkedList<T> list, int index)
		{
			if(list == null) throw new ArgumentNullException("list must be non-null");
			if(index >= list.Count || index < 0) throw new ArgumentOutOfRangeException("index is out of range: " + list.Count);
			int i = -1;
			LinkedListNode<T> link = list.First;
			while(link != null)
			{
				if(++i == index) return link;
				link = link.Next;
			}
			return null;
		}
		public static void ForEachNode<T>(this LinkedList<T> list, Action<LinkedListNode<T>> func)
		{
			LinkedListNode<T> target = list.First;
			while(target != null)
			{
				LinkedListNode<T> next = target.Next;
				
				func(target);
				
				target = next;
			}
		}
		public static void ForEach<T>(this LinkedList<T> list, Action<T> func)
		{
			LinkedListNode<T> target = list.First;
			while(target != null)
			{
				LinkedListNode<T> next = target.Next;
				
				func(target.Value);
				
				target = next;
			}
		}
		public static int IndexWhere<T>(this LinkedList<T> list, Func<T, bool> func)
		{
			LinkedListNode<T> target = list.First;
			int index = 0;
			while(target != null)
			{
				LinkedListNode<T> next = target.Next;
				
				if(func(target.Value)) return index;
				index++;
				
				target = next;
			}
			return -1;
		}
		public static int IndexOf<T>(this LinkedList<T> list, T item)
		{
			LinkedListNode<T> target = list.First;
			int index = 0;
			while(target != null)
			{
				LinkedListNode<T> next = target.Next;
				
				if(target.Value.Equals(item)) return index;
				index++;
				
				target = next;
			}
			return -1;
		}
		public static void Remove<T>(this LinkedList<T> list, Func<T, bool> func)
		{
			LinkedListNode<T> target = list.First;
			while(target != null)
			{
				LinkedListNode<T> next = target.Next;
				
				if(func(target.Value)) list.Remove(target);
				
				target = next;
			}
		}
		public static void RemoveOne<T>(this LinkedList<T> list, Func<T, bool> func)
		{
			LinkedListNode<T> target = list.First;
			while(target != null)
			{
				LinkedListNode<T> next = target.Next;
				
				if(func(target.Value))
				{
					list.Remove(target);
					return;
				}
				
				target = next;
			}
		}
		public static T Pop<T>(this LinkedList<T> list)
		{
			T value = list.Last.Value;
			list.RemoveLast();
			return value;
		}
		public static LinkedListNode<T> Push<T>(this LinkedList<T> list, T value)
		{
			return list.AddLast(value);
		}
		public static void Push<T>(this LinkedList<T> list, LinkedListNode<T> value)
		{
			list.AddLast(value);
		}
		public static SortedLinkedList<T> GetSorted<T>(this LinkedList<T> list)
		{
			SortedLinkedList<T> sorted = new SortedLinkedList<T>();
			foreach(T item in list) sorted.Add(item);
			return sorted;
		}
	}
}

